package org.unicen.exa.io.worker.assigner.input;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;
import org.unicen.exa.io.worker.assigner.core.model.Job;
import org.unicen.exa.io.worker.assigner.core.model.JobWorking;
import org.unicen.exa.io.worker.assigner.core.model.Worker;
import org.unicen.exa.io.worker.assigner.core.state.StatesConstants;
import org.unicen.exa.io.worker.assigner.dao.JobDao;
import org.unicen.exa.io.worker.assigner.dao.JobWorkingDao;
import org.unicen.exa.io.worker.assigner.dao.WorkerDao;


public class WorkerInstance implements Runnable {

	private Logger logger = Logger.getLogger(WorkerInstance.class);

	private JobWorkingDao<JobWorking> jobWorkingDao;
	private int timeInSecond;
	private WorkerDao<Worker> workerDao;
	private Worker worker;
	private JobDao<Job> jobDao;

	public WorkerInstance(Worker worker, WorkerDao<Worker> workerDao, JobWorkingDao<JobWorking> jobWorkingDao, JobDao<Job> jobDao, int timeInSecond) {
		this.timeInSecond = timeInSecond;
		this.jobWorkingDao = jobWorkingDao;
		this.workerDao = workerDao;
		this.worker = worker;
		this.jobDao = jobDao;

	}

	public void run() {
		logger.debug(String.format("SETTING instances with id=%s and state %s", worker.getId(), StatesConstants.WORKER_INSTANCES_BOOTING));
		worker.setState(StatesConstants.WORKER_INSTANCES_WORKING);
		workerDao.put(worker);
		ExecutorService executor = Executors.newScheduledThreadPool(2);
		boolean destroy;
		try {
			do {
				destroy = workerDao.get(worker.getId()).getState().equals(StatesConstants.WORKER_INSTANCES_DESTROYING);
				List<JobWorking> jobWorkins = jobWorkingDao.findByWorkerIdAndStatePending(worker.getId(), StatesConstants.JOB_WORKING_ASSIGN);
				for (JobWorking jobWorking : jobWorkins) {
					executor.submit(process(jobWorking));
				}

				Thread.sleep(timeInSecond * 1000);
			} while (!destroy);

		} catch (InterruptedException e) {
			e.printStackTrace();
			logger.error(e);
		}
	}

	private Runnable process(final JobWorking jobWorking) throws InterruptedException {
		
		return new Runnable(){
			
			
			public void run() {
					logger.debug(String.format("worker=%s is STARTING with job=%s", worker.getId(),jobWorking.getJobId()));
					
					
					logger.debug(String.format("RETRIEVING job with id=%s", jobWorking.getJobId()));
					Job job = jobDao.get(jobWorking.getJobId());
			
					//
					jobWorking.setStatus(StatesConstants.JOB_WORKING_STARTING);
					jobWorkingDao.put(jobWorking);
					job.setState(StatesConstants.JOB_STATE_TRANSCODING);
					jobDao.put(job);
					try {
						Thread.sleep(timeInSecond * 1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			
					//
					logger.debug(String.format("worker=%s is PROCESSING job=%s", worker.getId(),jobWorking.getJobId()));
					jobWorking.setStatus(StatesConstants.JOB_WORKING_PROCESSING);
					jobWorkingDao.put(jobWorking);
					jobDao.put(job);
					try {
						Thread.sleep(timeInSecond * 5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			
					//
					logger.debug(String.format("worker=%s is ENDING job=%s", worker.getId(),jobWorking.getJobId()));
					job.setState(StatesConstants.JOB_STATE_TRANSCODE);
					jobDao.put(job);
					jobWorking.setStatus(StatesConstants.JOB_WORKING_ENDING);
					jobWorkingDao.put(jobWorking);
					worker.setWeight(worker.getWeight() - job.getWeight());
					try {
						Thread.sleep(timeInSecond * 1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

			}
		};
	}
}
